#ifndef __FAST_RPC_FIFO_H__
#define __FAST_RPC_FIFO_H__

#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <memory>

#include "ret.h"
#include "config.h"
#include "request.h"

namespace fast_rpc
{

enum Role
{
    FIFO_ROLE_CREATOR = 0,
    FIFO_ROLE_USER = 1,
};

template <typename T, int ROLE=FIFO_ROLE_USER>
class FIFO
{

public:
    using PTR = std::unique_ptr<FIFO<T, ROLE>>;

    FIFO(const std::string& name): m_name(name) {}
    ~FIFO() {}

    FIFO(const FIFO&) = delete;

    Ret Init(const Config& config)
    {
        int ret = 0;
        int open_mode = O_WRONLY;

        if (ROLE == FIFO_ROLE_CREATOR) {
            int ret = mkfifo(m_name.c_str(), 0664);
            if (ret < 0 && (errno != EEXIST)) {
                LOG_ERROR("mkfifo failed, name: %s, err: %s", m_name.c_str(), strerror(errno));
                return RPC_FIFO_ERR_MKFIFO_FAILED;
            }
        } else {
            if (access(m_name.c_str(), F_OK) < 0) {
                LOG_ERROR("access fifo failed, name: %s, err: %s", m_name.c_str(), strerror(errno));
                return RPC_FIFO_ERR_ACCESS_FAILED;
            }
            open_mode = O_RDONLY;
        }

        // 打开FIFO，等待client请求
        m_fd = open(m_name.c_str(), open_mode);
        if (m_fd < 0) {
            LOG_ERROR("open fifo failed, name: %s, err: %s", m_name.c_str(), strerror(errno));
            return RPC_FIFO_ERR_OPEN_FAILED;
        }

        return Ret::RPC_SUCCESS;
    }

    Ret Destroy()
    {
        if (m_fd > 0) {
            close(m_fd);
            m_fd = -1;
        }

        return Ret::RPC_SUCCESS;
    }

    Ret Push(const T& data)
    {
        int bytes = write(m_fd, &data, sizeof(T));
        if (bytes != sizeof(T)) {
            LOG_ERROR("write fifo failed, name: %s, err: %s", m_name.c_str(), strerror(errno));
            return Ret::RPC_FIFO_ERR_WRITE_FAILED;
        }
        return Ret::RPC_SUCCESS;
    }

    Ret Pop(T& data)
    {
        int bytes = read(m_fd, &data, sizeof(T));
        if (bytes != sizeof(T)) {
            LOG_ERROR("write fifo failed, name: %s, err: %s", m_name.c_str(), strerror(errno));
            return Ret::RPC_FIFO_ERR_WRITE_FAILED;
        }
        return Ret::RPC_SUCCESS;
    }

private:
    std::string m_name;
    Config m_config;
    int m_fd;
    std::vector<std::string>  m_users;
}; // class PIPE


} // namespace fast_rpc

#endif // __FAST_RPC_FIFO_H__